package ck_log

import (
	"context"
	"fmt"
	"github.com/natefinch/lumberjack"
	"go-beego-api/exception"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
)

const (
	DOMAIN        = "Domain"        // 域 api/crontab/queue
	KINGDOM       = "Kingdom"       // 界 dev/prod
	PHYLUM        = "Phylum"        // 门 logic/mysql/redis/request
	CLASS         = "Class"         // 纲 队列名称,模块名称
	ORDER         = "Order"         // 目 corpId CID
	FAMILY        = "Family"        // 科 operate 实际操作人
	GENUS         = "Genus"         // 属 userId
	SPECIES       = "Species"       // 种 requestId
	EXECUTIONTIME = "ExecutionTime" // 执行时长
	RESPCODE      = "RespCode"      // 返回码
	VERSION       = "Version"       // 接口版本号
)

var Logger *zap.SugaredLogger

var SecLogger *zap.SugaredLogger

func InitZap(withStdout bool) {
	writer := zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout))
	infoLever := zapcore.DebugLevel
	if exception.RunMode != exception.DEV {
		if withStdout {
			writer = zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&LtvWriter{}))
		} else {
			infoLever = zapcore.InfoLevel
			writer = zapcore.NewMultiWriteSyncer(zapcore.AddSync(&LtvWriter{}))
		}
	}
	core := zapcore.NewCore(getEncoder(), writer, infoLever) // 设置日志的默认级别
	logger := zap.New(core, zap.AddCaller())
	Logger = logger.Sugar()
	if exception.RunMode == exception.PROD {
		initSec()
	}
}

func initSec() {
	infoLever := zapcore.InfoLevel
	writer := zapcore.NewMultiWriteSyncer(zapcore.AddSync(&LtvWriter{sec: true}))
	core := zapcore.NewCore(getEncoder(), writer, infoLever) // 设置日志的默认级别
	logger := zap.New(core, zap.AddCaller())
	SecLogger = logger.Sugar()
}

func InitFileZap(logpath string) {
	hook := lumberjack.Logger{
		Filename:   logpath, // 日志文件路径，默认 os.TempDir()
		MaxSize:    10,      // 每个日志文件保存10M，默认 100M
		MaxBackups: 5,       // 保留30个备份，默认不限
		MaxAge:     7,       // 保留7天，默认不限
		Compress:   false,   // 是否压缩，默认不压缩
	}

	writer := zapcore.AddSync(&hook)
	infoLever := zapcore.DebugLevel
	core := zapcore.NewCore(getEncoder(), writer, infoLever) // 设置日志的默认级别
	logger := zap.New(core, zap.AddCaller())
	Logger = logger.Sugar()
}

func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // 修改时间编码器

	// 在日志文件中使用大写字母记录日志级别
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	// NewConsoleEncoder 打印更符合人们观察的方式
	return zapcore.NewJSONEncoder(encoderConfig)
}

func LogCtx(ctx context.Context) *zap.SugaredLogger {
	if ctx == nil {
		ctx = CacheCtx()
	}
	l := Logger
	return parse(ctx, l)
}

func LogCtxSec(ctx context.Context) *zap.SugaredLogger {
	if ctx == nil {
		ctx = CacheCtx()
	}
	l := SecLogger
	return parse(ctx, l)
}

func parse(ctx context.Context, l *zap.SugaredLogger) *zap.SugaredLogger {
	if v, ok := ctx.Value(DOMAIN).(string); ok {
		l = l.With(DOMAIN, v)
	} else {
		ctx = CacheCtx()
		l = l.With(DOMAIN, exception.Domain)
	}
	if v, ok := ctx.Value(KINGDOM).(string); ok {
		l = l.With(KINGDOM, v)
	}
	if v, ok := ctx.Value(PHYLUM).(string); ok {
		l = l.With(PHYLUM, v)
	}
	if v, ok := ctx.Value(CLASS).(string); ok {
		l = l.With(CLASS, v)
	}
	if v, ok := ctx.Value(ORDER).(string); ok {
		l = l.With(ORDER, v)
	}
	if v, ok := ctx.Value(FAMILY).(string); ok {
		l = l.With(FAMILY, v)
	}
	if v, ok := ctx.Value(GENUS).(string); ok {
		l = l.With(GENUS, v)
	}
	if v, ok := ctx.Value(SPECIES).(string); ok {
		l = l.With(SPECIES, v)
	}
	if v, ok := ctx.Value(VERSION).(string); ok {
		l = l.With(VERSION, v)
	}
	return l
}

func CacheCtx() context.Context {
	return context.WithValue(context.WithValue(context.Background(), DOMAIN, exception.Domain), KINGDOM, exception.RunMode)
}

// todo 美化 traceErr 堆栈信息
func LogCtxErr(ctx context.Context, err error) *zap.SugaredLogger {
	l := LogCtx(ctx)
	errMsg := fmt.Sprintf("%+v", err)
	return l.With("traceErr", errMsg)
}
